﻿#region Copyright(c) 2006 ZO, All right reserved.
// -----------------------------------------------------------------------------
// Copyright(c) 2006 ZO, All right reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   1.  Redistribution of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//   2.  Redistribution in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//   3.  The name of the author may not be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// -----------------------------------------------------------------------------
#endregion


#region Using directives

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Deployment.Application;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Timers;
using System.Windows.Forms;
using ZO.SmartCore.Helpers;
using ZO.SmartCore.My4CSharp.Properties;
using ZO.SmartCore.Threading;
using ZO.SmartCore.Windows.Forms;
using ArgumentException= ZO.SmartCore.Core.ArgumentException;
using ArgumentNullException= ZO.SmartCore.Core.ArgumentNullException;
using SystemTimer = System.Timers.Timer;
using ZO.SmartCore.Logger;

#endregion

namespace ZO.SmartCore.My4CSharp
{
    /// <summary>Provides properties, methods, and events related to the current application.</summary>
    /// <filterpriority>1</filterpriority>
    [HostProtection(SecurityAction.LinkDemand, Resources = HostProtectionResource.ExternalProcessMgmt)]
    [Browsable(false)]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    public class WinFormApplication
    {

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="WinFormApplication"/> class.
        /// </summary>
        public WinFormApplication()
        {
            this._AppContext = new WinFormsAppContext(this);
        }
        #endregion

        #region Destructor

        #endregion

        #region Fields
        private static readonly ThreadSafeObjectProvider<AssemblyInfo> _AssemblyInfo = new ThreadSafeObjectProvider<AssemblyInfo>();


        private ReadOnlyCollection<string> _CommandLineArgs;
        private bool _EnableVisualStyles;
        private ShutdownMode _ShutdownStyle;
        private bool _IsSingleInstance;
        private ApplicationContext _AppContext;
        private int _MinimumSplashScreenDisplayTime = 250;
        private SmartForm _SplashScreen;
        private static readonly Mutex mutex = new Mutex(true, GetApplicationInstanceID(Assembly.GetCallingAssembly()));
        private const int SW_RESTORE = 9;
        private SystemTimer timer;
        private bool useModuleLoadingFlag = false;
        private readonly object m_SplashLock = new object();
        private bool _DidSplashScreen;
        private volatile bool _Ok2CloseSplashScreen = true;

        #endregion

        #region Delegates
        private delegate void DisposeDelegate();

        #endregion

        #region Events
        /// <summary>
        /// Occurs When application will loaded for first time;
        /// </summary>
        public event EventHandler Load;
        #endregion

        #region Operators

        #endregion

        #region Properties

        /// <summary>
        /// Returns the Log Object, which provides a property and methods for writing event and
        /// exception information to the application's event log.
        /// </summary>
        public Log<ConfigBasedLogProvider, ConfigBasedLogFormat> Log
        {
            get
            {
                return That.Log;
            }
        }


		/// <summary>
		/// Determines the minimum length of time, in milliseconds, for which the splash screen is displayed.
		/// </summary>
		/// <value>The minimum splash screen display time.</value>
		/// <returns>Integer. The minimum length of time, in milliseconds, for which the splash screen is displayed.</returns>
        [DefaultValue(250)]
        public int MinimumSplashScreenDisplayTime
        {
            get
            {
                return this._MinimumSplashScreenDisplayTime;
            }
            set
            {
                if (value > 250)
                {
                    this._MinimumSplashScreenDisplayTime = value;
                }
            }
        }

		/// <summary>
		/// Determines whether this application will use the XP Windows styles for windows, controls, and so on.
		/// </summary>
		/// <value><c>true</c> if [enable visual styles]; otherwise, <c>false</c>.</value>
		/// <returns>A <see cref="T:System.Boolean"></see> value that indicates whether this application will use the XP Windows styles for windows, controls, and so on.</returns>
        public bool EnableVisualStyles
        {
            get
            {
                return this._EnableVisualStyles;
            }
            set
            {
                this._EnableVisualStyles = value;
            }
        }

		/// <summary>
		/// Gets a collection of all the application's open forms.
		/// </summary>
		/// <value>The open forms.</value>
		/// <returns>A <see cref="T:System.Windows.Forms.FormCollection"></see> object that contains all of the application's open forms.</returns>
		/// <PermissionSet><IPermission class="System.Security.Permissions.UIPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Window="AllWindows"/></PermissionSet>
        public FormCollection OpenForms
        {
            get
            {
                return Application.OpenForms;
            }
        }

		/// <summary>
		/// Gets the culture that the current thread uses for string manipulation and string formatting.
		/// </summary>
		/// <value>The culture.</value>
		/// <returns>Returns a <see cref="T:System.Globalization.CultureInfo"></see> object that represents the culture the current thread uses for string manipulation and string formatting.</returns>
        public CultureInfo Culture
        {
            get
            {
                return Thread.CurrentThread.CurrentCulture;
            }
        }

		/// <summary>
		/// Gets an object that provides properties for getting information about the application's assembly, such as the version number, description, and so on.
		/// </summary>
		/// <value>The info.</value>
		/// <returns>This property returns the My.Application.Info object for the current application.</returns>
        public AssemblyInfo Info
        {
            [HostProtection(SecurityAction.LinkDemand, Resources = HostProtectionResource.ExternalProcessMgmt)]
            get
            {
                if (!(_AssemblyInfo.Created))
                {
                    Assembly assembly1 = Assembly.GetEntryAssembly();
                    if (assembly1 == null)
                    {
                        assembly1 = Assembly.GetCallingAssembly();
                    }
                    _AssemblyInfo.CreateInstance(assembly1);
                }
                return _AssemblyInfo.Instance;
            }
        }

		/// <summary>
		/// Gets the culture that the current thread uses for retrieving culture-specific resources.
		/// </summary>
		/// <value>The UI culture.</value>
		/// <returns>Returns a <see cref="T:System.Globalization.CultureInfo"></see> object that represents the culture that the current thread uses for retrieving culture-specific resources.</returns>
        public CultureInfo UICulture
        {
            get
            {
                return Thread.CurrentThread.CurrentUICulture;
            }
        }


		/// <summary>
		/// Gets a collection containing the command-line arguments as strings for the current application.
		/// </summary>
		/// <value>The command line args.</value>
		/// <returns>A <see cref="T:System.Collections.ObjectModel.ReadOnlyCollection`1"></see> of String, containing the command-line arguments as strings for the current application.</returns>
        public ReadOnlyCollection<string> CommandLineArgs
        {
            get
            {
                if (this._CommandLineArgs == null)
                {
                    string[] textArray1 = Environment.GetCommandLineArgs();
                    if (textArray1.GetLength(0) >= 2)
                    {
                        string[] textArray2 = new string[(textArray1.GetLength(0) - 2) + 1];
                        Array.Copy(textArray1, 1, textArray2, 0, textArray1.GetLength(0) - 1);
                        this._CommandLineArgs = new ReadOnlyCollection<string>(textArray2);
                    }
                    else
                    {
                        this._CommandLineArgs = new ReadOnlyCollection<string>(new string[0]);
                    }
                }
                return this._CommandLineArgs;
            }
        }
		/// <summary>
		/// Gets the current application's ClickOnce deployment object, which provides support for updating the current deployment programmatically and support for the on-demand download of files.
		/// </summary>
		/// <value>The deployment.</value>
		/// <returns>Returns the <see cref="T:System.Deployment.Application.ApplicationDeployment"></see> object for the application's ClickOnce deployment.</returns>
        public ApplicationDeployment Deployment
        {
            get
            {
                return ApplicationDeployment.CurrentDeployment;
            }
        }

		/// <summary>
		/// Sets the values to use as the current application's command-line arguments.
		/// </summary>
		/// <value>The internal command line.</value>
		/// <returns>A <see cref="T:System.Collections.ObjectModel.ReadOnlyCollection`1"></see> of String, containing the strings to use as the command-line arguments for the current application.</returns>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected ReadOnlyCollection<string> InternalCommandLine
        {
            set
            {
                this._CommandLineArgs = value;
            }
        }

		/// <summary>
		/// Gets a Boolean that represents whether the application was deployed from a network using ClickOnce.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is network deployed; otherwise, <c>false</c>.
		/// </value>
		/// <returns>A Boolean that represents whether the application was deployed from a network. The value is True if the current application was deployed from a network; otherwise the value is False.</returns>
        public bool IsNetworkDeployed
        {
            get
            {
                return ApplicationDeployment.IsNetworkDeployed;
            }
        }
		/// <summary>
		/// Determines what happens when the application's main form closes.
		/// </summary>
		/// <value>The shutdown style.</value>
		/// <returns>A <see cref="ShutdownMode"></see> enumeration value, indicating what the application should do when the main form closes.</returns>
        public ShutdownMode ShutdownStyle
        {
            get
            {
                return this._ShutdownStyle;
            }
            set
            {
                this._ShutdownStyle = value;
            }
        }

		/// <summary>
		/// Gets the <see cref="T:System.Windows.Forms.ApplicationContext"></see> object for the current thread of a Windows Forms application.
		/// </summary>
		/// <value>The application context.</value>
		/// <returns>This property returns the <see cref="T:System.Windows.Forms.ApplicationContext"></see> object for the current thread. That object contains contextual information about the thread.</returns>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public ApplicationContext ApplicationContext
        {
            get
            {
                return this._AppContext;
            }
        }

		/// <summary>
		/// Determines whether this application is a single-instance application.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance is single instance; otherwise, <c>false</c>.
		/// </value>
		/// <returns>A <see cref="T:System.Boolean"></see> value that indicates whether this application is a single-instance application.</returns>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        public bool IsSingleInstance
        {
            get
            {
                return this._IsSingleInstance;
            }
            set
            {
                this._IsSingleInstance = value;
            }
        }


		/// <summary>
		/// Gets or sets the main form for this application.
		/// </summary>
		/// <value>The main form.</value>
		/// <returns>Gets or sets the main form for this application.</returns>
        public SmartForm MainForm
        {
            get
            {
                return this._AppContext != null ? this._AppContext.MainForm as SmartForm : null;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("MainForm");
                }
                if (value == this._SplashScreen)
                {
                    throw new ArgumentException(Resources.AppModel_SplashAndMainFormTheSame);
                }
                this._AppContext.MainForm = value;
            }
        }

		/// <summary>
		/// Gets or sets the splash screen for this application.
		/// </summary>
		/// <value>The splash form.</value>
		/// <returns>A <see cref="T:System.Windows.Forms.Form"></see> object that the application uses as the splash screen.</returns>
        public SmartForm SplashForm
        {
            get
            {
                return this._SplashScreen;
            }
            set
            {
                if ((value != null) && (value == this._AppContext.MainForm))
                {
                    throw new ArgumentException(Resources.AppModel_SplashAndMainFormTheSame);

                }
                this._SplashScreen = value;
            }
        }

        #endregion

        #region Methods

        #region OnLoad
        /// <summary>
        /// Triggers the Load event.
        /// </summary>
        protected virtual void OnLoad()
        {
            if (Load != null)
            {
                Load(this, EventArgs.Empty);
            }

        }
        #endregion


		/// <summary>
		/// Gets the path for the executable file that started the application.
		/// </summary>
		/// <value>The path for the executable file that started the application.</value>
        public string ExecutablePath
        {
            get
            {
                string exePath = Application.ExecutablePath;

                return Path.GetDirectoryName(exePath);
            }
        }

		/// <summary>
		/// Gets the path for the executable file that started the application, including the executable name.
		/// </summary>
		/// <value>
		/// The path and executable name for the executable file that started the application.
		/// </value>
        public string ExecutableFilePath
        {
            get
            {
                return Application.ExecutablePath;

            }
        }

		/// <summary>
		/// Changes the culture used by the current thread for string manipulation and for string formatting.
		/// </summary>
		/// <param name="cultureName">String. Name of the culture as a string. For a list of possible names, see <see cref="T:System.Globalization.CultureInfo"></see>.</param>
        [HostProtection(SecurityAction.LinkDemand, Resources = HostProtectionResource.ExternalProcessMgmt)]
        public void ChangeCulture(string cultureName)
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureName);
        }


		/// <summary>
		/// Changes the culture that the current thread uses for retrieving culture-specific resources.
		/// </summary>
		/// <param name="cultureName">String. Name of the culture as a string. For a list of possible names, see <see cref="T:System.Globalization.CultureInfo"></see>.</param>
        public void ChangeUICulture(string cultureName)
        {
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(cultureName);
        }


        /// <summary>Returns the value of the specified environment variable.</summary>
        /// <returns>A String containing the value of the environment variable with the name name.</returns>
        /// <param name="name">A String containing the name of the environment variable.</param>
        /// <filterpriority>1</filterpriority>
        /// <PermissionSet><IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /></PermissionSet>
        public string GetEnvironmentVariable(string name)
        {
            string text2 = Environment.GetEnvironmentVariable(name);
            if (text2 == null)
            {
                throw new ArgumentException("name", Resources.EnvVarNotFound_Name, name);
            }
            return text2;
        }


		/// <summary>
		/// Processes all Windows messages currently in the message queue.
		/// </summary>
		/// <PermissionSet><IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence"/></PermissionSet>
        public void DoEvents()
        {
            Application.DoEvents();
        }


		/// <summary>
		/// Sets the visual styles, text display styles, and current principal for the main application thread (if the application uses Windows authentication), and initializes the splash screen, if defined.
		/// </summary>
		/// <param name="commandLineArgs">A <see cref="T:System.Collections.ObjectModel.ReadOnlyCollection`1"></see> of String, containing the command-line arguments as strings for the current application.</param>
		/// <returns>
		/// A <see cref="T:System.Boolean"></see> indicating if application startup should continue.
		/// </returns>
        [EditorBrowsable(EditorBrowsableState.Advanced), STAThread]
        protected virtual bool OnInitialize(ReadOnlyCollection<string> commandLineArgs)
        {
            if (this.EnableVisualStyles)
            {
                Application.EnableVisualStyles();
            }

            if (!commandLineArgs.Contains("/nosplash") && !this.CommandLineArgs.Contains("-nosplash"))
            {
                this.ShowSplashScreen();

            }
            return true;
        }





		/// <summary>
		/// Does the application model.
		/// </summary>
        private void DoApplicationModel()
        {
            if (this.OnInitialize(this.CommandLineArgs))
            {
                this.OnRun();
                //this.OnShutdown();
            }
        }

		/// <summary>
		/// When overridden in a derived class, allows a designer to emit code that initializes the splash screen.
		/// </summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnCreateSplashScreen()
        {
        }


		/// <summary>
		/// Minimums the splash exposure time is up.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="T:System.Timers.ElapsedEventArgs"/> instance containing the event data.</param>
        private void MinimumSplashExposureTimeIsUp(object sender, ElapsedEventArgs e)
        {
            if (this.timer != null)
            {
                this.timer.Dispose();
                this.timer = null;
            }

            if (MainForm is SmartMainForm)
            {
                if (!useModuleLoadingFlag)
                {
                    this.useModuleLoadingFlag = true;
                    Thread.Sleep(100);
                }
                else
                {
                    this._Ok2CloseSplashScreen = true;
                }
            }
            else
            {
                this._Ok2CloseSplashScreen = true;
            }

        }




		/// <summary>
		/// Determines if the application has a splash screen defined, and if it does, displays it.
		/// </summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected void ShowSplashScreen()
        {
            if (!this._DidSplashScreen)
            {
                this._DidSplashScreen = true;
                if (this._SplashScreen == null)
                {
                    this.OnCreateSplashScreen();
                }
                if (this._SplashScreen != null)
                {
                    if (this._MinimumSplashScreenDisplayTime > 0)
                    {
                        this._Ok2CloseSplashScreen = false;
                        this.timer = new SystemTimer(this.MinimumSplashScreenDisplayTime);
                        this.timer.Elapsed += new ElapsedEventHandler(this.MinimumSplashExposureTimeIsUp);
                        this.timer.AutoReset = false;
                    }
                    else
                    {
                        this._Ok2CloseSplashScreen = true;
                    }
                    new Thread(new ThreadStart(this.DisplaySplash)).Start();
                }
            }
        }


        private void DisplaySplash()
        {
            if (this.timer != null)
            {
                this.timer.Enabled = true;
            }
            Application.Run(this.SplashForm);
            
        }




		/// <summary>
		/// Provides the starting point for when the main application is ready to start running, after the initialization is done.
		/// </summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnRun()
        {
            if (this.MainForm == null)
            {
                this.OnCreateMainForm();
                if (this.MainForm == null)
                {
                    throw new NoStartupFormException();
                }

            }

            this.MainForm.Load += new EventHandler(MainForm_Load);

            if (MainForm is SmartMainForm)
            {
                ((SmartMainForm)this.MainForm).ModuleLoadingStarted += new EventHandler(MainForm_ModuleLoadingStarted);
                ((SmartMainForm)this.MainForm).LoadingModule += new EventHandler<ModuleEventArgs>(MainForm_LoadingModule);
                ((SmartMainForm)this.MainForm).ModuleLoadingCompleted += new EventHandler(MainForm_ModuleLoadingCompleted);
            }


            Application.Run(this.ApplicationContext);
        }


		/// <summary>
		/// Handles the LoadingModule event of the MainForm control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="T:SmartCore.Windows.Forms.ModuleEventArgs"/> instance containing the event data.</param>
        private void MainForm_LoadingModule(object sender, ModuleEventArgs e)
        {
            if (SplashForm != null)
            {
                this.SplashForm.Invoke((ThreadStart)delegate { ((SmartSplashForm)this.SplashForm).SetStatus(e.Name); }); 

                //if (this.SplashForm.InvokeRequired)
                //{
                //    if (SplashForm is SmartSplashForm)
                //    {
                //        ((SmartSplashForm)this.SplashForm).Invoke(new SetStatusDelegate(((SmartSplashForm)this.SplashForm).SetStatus), e.Name);
                //    }

                //}
                //else
                //{
                //    if (SplashForm is SmartSplashForm)
                //    {

                //        ((SmartSplashForm)this.SplashForm).SetStatus(e.Name);
                //    }
                //}
                Thread.Sleep(100);
            }

        }

        /// <summary>
        /// Handles the ModuleLoadingStarted event of the MainForm control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void MainForm_ModuleLoadingStarted(object sender, EventArgs e)
        {
            if (MainForm is SmartMainForm)
            {

                ((SmartMainForm)this.MainForm).ModuleLoadingStarted -= new EventHandler(MainForm_ModuleLoadingStarted);

            }
            if (SplashForm != null)
            {

                //this.SplashForm.Invoke((ThreadStart)delegate { ((SmartSplashForm)this.SplashForm).SetStatus("Loading ..."); }); 

                if (this.SplashForm.InvokeRequired)
                {
                    if (SplashForm is SmartSplashForm)
                    {
                        this.SplashForm.Invoke(new SetStatusDelegate(((SmartSplashForm)this.SplashForm).SetStatus), "Loading ...");
                    }

                }
                else
                {
                    if (SplashForm is SmartSplashForm)
                    {

                        ((SmartSplashForm)this.SplashForm).SetStatus("Loading ...");
                    }
                }
            }
            Thread.Sleep(250);
          
            useModuleLoadingFlag = false;


        }

		/// <summary>
		/// Handles the ModuleLoadingCompleted event of the MainForm control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void MainForm_ModuleLoadingCompleted(object sender, EventArgs e)
        {
            if (MainForm is SmartMainForm)
            {

                ((SmartMainForm)this.MainForm).LoadingModule -= new EventHandler<ModuleEventArgs>(MainForm_LoadingModule);

            }

			if (SplashForm != null)
			{

				if (this.SplashForm.InvokeRequired)
				{
					if (SplashForm is SmartSplashForm)
					{
						this.SplashForm.Invoke(new SetStatusDelegate(((SmartSplashForm)this.SplashForm).SetStatus), StringHelper.Format("Starting {0}", this.Info.ProductName));
					}

				}
				else
				{
					if (SplashForm is SmartSplashForm)
					{

						((SmartSplashForm)this.SplashForm).SetStatus(StringHelper.Format("Starting {0}", this.Info.ProductName));


					}
				}



				if (MainForm is SmartMainForm)
				{

					((SmartMainForm)this.MainForm).ModuleLoadingCompleted -= new EventHandler(MainForm_ModuleLoadingCompleted);

				}


				if (!useModuleLoadingFlag)
				{
					this.useModuleLoadingFlag = true;
				}
				else
				{
					this._Ok2CloseSplashScreen = true;
				}

				Thread.Sleep(300);

			}
		}

		/// <summary>
		/// Handles the Load event of the MainForm control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="T:System.EventArgs"/> instance containing the event data.</param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            this.MainForm.Load -= new EventHandler(this.MainForm_Load);
            while (!this._Ok2CloseSplashScreen)
            {
                this.DoEvents();
            }
            this.HideSplashScreen();
            this.DoEvents();
            this.OnLoad();
            this.DoEvents();
        }

        /// <summary>Hides the application's splash screen.</summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected void HideSplashScreen()
        {
            lock (m_SplashLock)
            {
                if ((this.SplashForm != null) && !this.SplashForm.IsDisposed)
                {
                    DisposeDelegate delegate1 = new DisposeDelegate(this.SplashForm.Dispose);



                    if (this.SplashForm.InvokeRequired)
                    {
                        this.SplashForm.Invoke(delegate1);
                    }
                    else
                    {
                        this.SplashForm.Dispose();
                    }

                    this.SplashForm = null;
                }
                if (this.MainForm != null)
                {
                    new UIPermission(UIPermissionWindow.AllWindows).Assert();
                    this.MainForm.Activate();
                    PermissionSet.RevertAssert();
                }
            }
        }

 



        /// <summary>When overridden in a derived class, allows a designer to emit code that configures the splash screen and main form.</summary>
        [EditorBrowsable(EditorBrowsableState.Advanced)]
        protected virtual void OnCreateMainForm()
        {
        }

 



        /// <summary>Sets up and starts the Visual Basic Application model. </summary>
        /// <param name="args">Array of type String. The command line from Sub Main.</param>
        /// <PermissionSet><IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /><IPermission class="System.Security.Permissions.RegistryPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="UnmanagedCode, ControlEvidence, ControlPrincipal, RemotingConfiguration" /><IPermission class="System.Net.NetworkInformation.NetworkInformationPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Access="Read" /><IPermission class="System.Net.SocketPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /><IPermission class="System.Diagnostics.PerformanceCounterPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" /></PermissionSet>
        public void Run(params object[] args)
        {
            string[] commandLine = new string[args.Length];
            Array.Copy(args, commandLine, args.Length);
            
            this.InternalCommandLine = new ReadOnlyCollection<string>(commandLine);


            if (this.IsSingleInstance)
            {
                if (mutex.WaitOne(0, false))
                {
                    this.DoApplicationModel();
                }
                else
                {
                    //application already running set focus to running instance
                    SetFocusToPreviousInstance(this.ApplicationContext.MainForm.Text);
                }

            }
            else
            {
                this.DoApplicationModel();

				//set focus to running instance
				//this.MainForm.Activate();
				SetFocusToPreviousInstance(this.ApplicationContext.MainForm.Text);

            }
        }

		/// <summary>
		/// Gets the application instance ID.
		/// </summary>
		/// <param name="Entry">The entry.</param>
		/// <returns></returns>
        private static string GetApplicationInstanceID(Assembly Entry)
        {
            PermissionSet set1 = new PermissionSet(PermissionState.None);
            set1.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
            set1.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
            set1.Assert();
            Guid guid1 = Marshal.GetTypeLibGuidForAssembly(Entry);
            string[] textArray1 = Entry.GetName().Version.ToString().Split('.');
            PermissionSet.RevertAssert();
            return (guid1.ToString() + textArray1[0] + "." + textArray1[1]);
        }

        /// <summary>
        ///  Set focus to the previous instance of the specified program.
        /// </summary>
        /// <param name="windowCaption"></param>
        private static void SetFocusToPreviousInstance(string windowCaption)
        {
            // Look for previous instance of this program.
            IntPtr hWnd = UnsafeNativeMethods.FindWindow(null, windowCaption);

            // If a previous instance of this program was found...
            if (hWnd != null & hWnd != IntPtr.Zero)
            {
                // Is it displaying a popup window?
                IntPtr hPopupWnd = UnsafeNativeMethods.GetLastActivePopup(hWnd);

                // If so, set focus to the popup window. Otherwise set focus
                // to the program's main window.
                if (hWnd != null & hWnd != IntPtr.Zero & SafeNativeMethods.IsWindowEnabled(hPopupWnd))
                {
                    hWnd = hPopupWnd;
                }

                UnsafeNativeMethods.SetForegroundWindow(hWnd);

                // If program is minimized, restore it.
                if (SafeNativeMethods.IsIconic(hWnd))
                {
                    SafeNativeMethods.ShowWindow(hWnd, SW_RESTORE);
                }
            }
        }
#endregion

        #region WinFormsAppContext

        private class WinFormsAppContext : ApplicationContext
        {
            public WinFormsAppContext(WinFormApplication App)
            {
                this._Application = App;
            }


  


            protected override void OnMainFormClosed(object sender, EventArgs e)
            {
                if (this._Application.ShutdownStyle == ShutdownMode.AfterMainFormCloses)
                {
                    base.OnMainFormClosed(sender, e);
                }
                else
                {
                    new UIPermission(UIPermissionWindow.AllWindows).Assert();
                    FormCollection collection1 = Application.OpenForms;
                    PermissionSet.RevertAssert();
                    if (collection1.Count > 0)
                    {
                        this.MainForm = collection1[0];
                    }
                    else
                    {
                        base.OnMainFormClosed(sender, e);
                    }
                }
            }



            private WinFormApplication _Application;
        }

        #endregion

    }
}
